package jlib.component.animation
{
	import flash.display.DisplayObject;
	import flash.display.Shape;
	import flash.events.Event;
	
	import jlib.component.IHandler;
	import jlib.core.IRenderable;
	import jlib.utils.Clock;

	/**
	 * Animation 추상 클래스. 
	 */	
	[Abstract] public class Animation implements IRenderable, IHandler
	{
		static internal var g_stepper:Shape = new Shape();
		static internal var g_observer:Array = new Array();
		static internal var g_time:Number = 0;
		
		internal var i_bRegisted:Boolean;
		internal var i_bStop:Boolean;
		internal var i_target:DisplayObject;
		internal var i_time:Number;
		internal var i_easing:Function;
		internal var i_yoyo:Boolean;
		internal var i_duration:Number;
		internal var i_bReverse:Boolean;
		
		public function Animation($target:DisplayObject=null, $duration:Number=NaN, $easing:Function=null, $yoyo:Boolean=false){
			target($target);
			duration($duration);
			i_easing = $easing;
			i_yoyo = $yoyo;
			i_time = 0;
		}
		
		public function start($param:*=null): void { throw new Error("Abstract"); }
		public function move($step:*):void { throw new Error("Abstract");}
		public function stop($param:*=null):void { i_bStop = true; }
		
		public function render($elapsed:Number):void {
			i_time += $elapsed;
			if(escape()) return ;
			var rate:Number = i_time/i_duration;
			if(i_bReverse) rate = (i_duration-i_time)/i_duration;
			move(rate);
		}
		
		public function duration($duration:Number): void { i_duration = $duration; }
		public function target($target:DisplayObject): void { i_target = $target; }
		public function easing($easing:Function): void { i_easing = $easing; }
		public function yoyo($yoyo:Boolean): void { i_yoyo = $yoyo; }
		public function reset(): void {  i_time = 0;  }
		public function dealloc(): void { target(null); }
		public function isStop(): Boolean { return i_bStop; }
		
		private function escape(): Boolean {
			if(i_time >= i_duration) {
				stop();
				i_time = i_duration;
				move(int(!i_bReverse));
				return true;
			}
			return false;
		}

		public function reverse():void  { i_bReverse = !i_bReverse; }
		
		final public function regist(): void {
			if(i_bRegisted) return ;
			if(!g_stepper.hasEventListener(Event.ENTER_FRAME)){
				g_stepper.addEventListener(Event.ENTER_FRAME, onTimeStep );
			}
			g_observer.push(this);
			i_bRegisted = true;
		}
		
		final public function unregist(): void {
			g_observer.splice(g_observer.indexOf(this),1);
			i_bRegisted = false;
			dealloc();
		}
		
		static internal function onTimeStep($event:Event): void {
			var elapsed:Number = Clock.elapsed()
			for(var i:int=0;i<g_observer.length;++i){
				var ani:Animation = g_observer[i];
				if(ani.isStop()) continue ;
				ani.render(elapsed);
			}
			g_time += elapsed;
		}
		
	}//c
}